Skip to content

feat(ensindexer): per-chain end blocks via END_BLOCK_<chainId>#2176

Open
shrugs wants to merge 1 commit into
mainfrom
feat/per-chain-end-blocks
Open

feat(ensindexer): per-chain end blocks via END_BLOCK_<chainId>#2176
shrugs wants to merge 1 commit into
mainfrom
feat/per-chain-end-blocks

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented May 21, 2026

Add END_BLOCK_<chainId> env vars (mirroring RPC_URL_<chainId>) parsed into config.chainEndBlocks: Map<ChainId, number>. Each constrains its chain's indexing end block independently, layered on top of the global blockrange (lower end wins), resolved per chain via blockrangeForChain() in ponder-helpers.

Unlike the global START_BLOCK/END_BLOCK — still restricted to single-chain indexing by invariant_globalBlockrange — per-chain end blocks MAY be set across multiple indexed chains (new invariant_chainEndBlocks only checks each chain is indexed). This enables deterministic, reproducible multichain checkpoints where every chain stops at a block corresponding to a shared timestamp.

@shrugs shrugs requested a review from a team as a code owner May 21, 2026 21:09
Copilot AI review requested due to automatic review settings May 21, 2026 21:09
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment May 21, 2026 9:39pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment May 21, 2026 9:39pm
ensnode.io Ready Ready Preview, Comment May 21, 2026 9:39pm
ensrainbow.io Ready Ready Preview, Comment May 21, 2026 9:39pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 21, 2026

🦋 Changeset detected

Latest commit: 7aa4410

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
ensindexer Minor
@ensnode/ensnode-sdk Minor
ensapi Minor
ensrainbow Minor
fallback-ensapi Minor
@namehash/ens-referrals Minor
@ensnode/ensdb-sdk Minor
@ensnode/ensrainbow-sdk Minor
@ensnode/integration-test-env Minor
@namehash/namehash-ui Minor
ensadmin Minor
@docs/ensnode Minor
@docs/ensrainbow Minor
enssdk Minor
enscli Minor
enskit Minor
ensskills Minor
@ensnode/datasources Minor
@ensnode/ponder-sdk Minor
@ensnode/ponder-subgraph Minor
@ensnode/shared-configs Minor
@ensnode/ensindexer-perf-testing Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Warning

Rate limit exceeded

@shrugs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 35 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 32230ed4-9a11-44cf-a6fe-256d7fd9426c

📥 Commits

Reviewing files that changed from the base of the PR and between 49400ce and 7aa4410.

📒 Files selected for processing (24)
  • .changeset/ensindexer-per-chain-end-blocks.md
  • .changeset/ensnode-sdk-indexed-blockranges-per-chain.md
  • apps/ensindexer/src/config/config.schema.ts
  • apps/ensindexer/src/config/config.test.ts
  • apps/ensindexer/src/config/environment.ts
  • apps/ensindexer/src/config/serialize.ts
  • apps/ensindexer/src/config/serialized-types.ts
  • apps/ensindexer/src/config/types.ts
  • apps/ensindexer/src/config/validations.ts
  • apps/ensindexer/src/lib/__test__/mockConfig.ts
  • apps/ensindexer/src/lib/local-ponder-client.ts
  • apps/ensindexer/src/lib/ponder-helpers.test.ts
  • apps/ensindexer/src/lib/ponder-helpers.ts
  • apps/ensindexer/src/plugins/protocol-acceleration/plugin.ts
  • apps/ensindexer/src/plugins/registrars/plugin.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/basenames/plugin.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/lineanames/plugin.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/subgraph/plugin.ts
  • apps/ensindexer/src/plugins/subgraph/plugins/threedns/plugin.ts
  • apps/ensindexer/src/plugins/tokenscope/plugin.ts
  • apps/ensindexer/src/plugins/unigraph/plugin.ts
  • apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts
  • packages/ensnode-sdk/src/shared/config/indexed-blockranges.test.ts
  • packages/ensnode-sdk/src/shared/config/indexed-blockranges.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/per-chain-end-blocks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support to ENSIndexer for per-chain indexing end blocks via END_BLOCK_<chainId> environment variables, enabling deterministic multi-chain checkpointing by constraining each chain independently (layered on top of the existing global START_BLOCK/END_BLOCK behavior).

Changes:

  • Introduces config.chainEndBlocks: Map<ChainId, number> parsed from END_BLOCK_<chainId> env vars, validated via a new invariant_chainEndBlocks.
  • Adds blockrangeForChain() and threads chainEndBlocks through chainConfigForContract() / mergedChainConfigForContracts() so plugin contract configs respect per-chain end blocks.
  • Updates plugins and tests to use the per-chain effective blockrange where needed (including Resolver configs built via constrainBlockrange(...)).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
apps/ensindexer/src/plugins/unigraph/plugin.ts Passes chainEndBlocks into chain config helpers and applies per-chain blockrange when constraining Resolver ranges.
apps/ensindexer/src/plugins/tokenscope/plugin.ts Passes chainEndBlocks into chainConfigForContract for all configured contracts/chains.
apps/ensindexer/src/plugins/subgraph/plugins/threedns/plugin.ts Threads chainEndBlocks into chain config helper calls for 3DNS contracts on multiple chains.
apps/ensindexer/src/plugins/subgraph/plugins/subgraph/plugin.ts Updates subgraph plugin contract configs to respect per-chain end blocks.
apps/ensindexer/src/plugins/subgraph/plugins/lineanames/plugin.ts Updates lineanames subgraph plugin configs to include per-chain end blocks.
apps/ensindexer/src/plugins/subgraph/plugins/basenames/plugin.ts Updates basenames subgraph plugin configs to include per-chain end blocks.
apps/ensindexer/src/plugins/registrars/plugin.ts Threads chainEndBlocks into registrar-related contract config helpers, including merged registrar controller config.
apps/ensindexer/src/plugins/protocol-acceleration/plugin.ts Passes chainEndBlocks into chain config helpers and applies per-chain blockrange to Resolver constraints.
apps/ensindexer/src/lib/ponder-helpers.ts Adds blockrangeForChain() and layers per-chain end blocks into chainConfigForContract and mergedChainConfigForContracts.
apps/ensindexer/src/lib/ponder-helpers.test.ts Adds focused unit tests for blockrangeForChain().
apps/ensindexer/src/config/validations.ts Adds invariant_chainEndBlocks to ensure each END_BLOCK_<chainId> corresponds to an indexed chain.
apps/ensindexer/src/config/types.ts Extends EnsIndexerConfig with chainEndBlocks and documents its semantics/invariants.
apps/ensindexer/src/config/serialized-types.ts Excludes chainEndBlocks from the serialized config type (since it’s a Map).
apps/ensindexer/src/config/environment.ts Extends the environment type to allow END_BLOCK_<number> keys.
apps/ensindexer/src/config/config.test.ts Adds config parsing/validation tests for END_BLOCK_<chainId> (multi-chain allowed, non-indexed chain rejected, negative/non-numeric rejected).
apps/ensindexer/src/config/config.schema.ts Implements buildChainEndBlocksFromEnv, adds schema support for chainEndBlocks, and wires in the new invariant.
.changeset/ensindexer-per-chain-end-blocks.md Changeset describing the new per-chain end block feature and semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to +85
const endBlock = Number(value);
if (!Number.isInteger(endBlock) || endBlock < 0) {
throw new Error(`${key} must be a non-negative integer.`);
}

chainEndBlocks.set(Number(match[1]), endBlock);
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 21, 2026

Greptile Summary

This PR replaces the single-global START_BLOCK/END_BLOCK constraint (limited to single-chain indexing) with per-chain END_BLOCK_<chainId> environment variables parsed into config.chainEndBlocks: Map<ChainId, number>, mirroring the existing RPC_URL_<chainId> pattern. The new blockrangeForChain() helper resolves the per-chain end block for each contract, and a new invariant_chainEndBlocks validation ensures every configured chain is actually indexed.

  • New env convention: END_BLOCK_1, END_BLOCK_8453, etc. are scanned via regex in buildChainEndBlocksFromEnv, validated, and stored as a Map<ChainId, number> propagated throughout all plugins.
  • Multichain support: Unlike the old global blockrange (which enforced single-chain-only when set), per-chain end blocks may be applied simultaneously across any number of indexed chains, enabling deterministic multichain checkpoints.
  • Ponder build-ID serialization: The Map is converted to a key-sorted plain object in indexing-behavior-injection-contract.ts so it contributes a stable, non-empty checksum to Ponder's build ID.

Confidence Score: 5/5

Safe to merge — per-chain end-block logic is consistently applied across all plugins and the new invariant correctly guards against misconfigured chain IDs.

The replacement of globalBlockrange with chainEndBlocks is mechanically consistent across all plugins. Core validation, parsing, range resolution, and Ponder build-ID serialization are all correct. Tests cover the main paths. The two suggestions are usability polish, not correctness issues.

apps/ensindexer/src/config/serialized-types.ts omits chainEndBlocks with no replacement, leaving per-chain end-block state invisible in the serialized config output.

Important Files Changed

Filename Overview
apps/ensindexer/src/config/config.schema.ts Introduces buildChainEndBlocksFromEnv to parse END_BLOCK_<chainId> env vars into a Map; replaces BlockrangeSchema/globalBlockrange in the schema and build function. Logic is correct; throws for non-integer values before Zod validation runs.
apps/ensindexer/src/config/validations.ts Replaces invariant_globalBlockrange with invariant_chainEndBlocks; the stale 'in the future' error message is fully removed.
apps/ensindexer/src/lib/ponder-helpers.ts Adds blockrangeForChain helper; updates chainConfigForContract and mergedChainConfigForContracts to accept ReadonlyMap<ChainId, number>. All call sites updated consistently.
apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts Serializes chainEndBlocks Map to a key-sorted plain object for a stable Ponder build ID. Sorting uses correct numeric comparator.
packages/ensnode-sdk/src/shared/config/indexed-blockranges.ts Updates buildIndexedBlockranges to accept ReadonlyMap<ChainId, number>; skip and cap logic correctly scoped per chain.
apps/ensindexer/src/config/serialized-types.ts Adds chainEndBlocks to the Omit list with no serialized replacement, making per-chain end-block config invisible in serialized output.
apps/ensindexer/src/config/environment.ts Removes START_BLOCK/END_BLOCK; adds template literal index signature `[x: 'END_BLOCK_${number}']: string
apps/ensindexer/src/config/types.ts Replaces globalBlockrange: BlockNumberRange with chainEndBlocks: Map<ChainId, number>; documentation accurately reflects new semantics.
apps/ensindexer/src/config/config.test.ts Thorough test coverage for chainEndBlocks: defaults, single-chain, multi-chain, invalid target, negative, and non-numeric values.
apps/ensindexer/src/lib/ponder-helpers.test.ts Three unit tests for blockrangeForChain covering unbounded, right-bounded, and chain-isolation cases.

Reviews (2): Last reviewed commit: "feat(ensindexer): per-chain end blocks v..." | Re-trigger Greptile

Comment on lines 28 to +32
export interface SerializedENSIndexerConfig
extends Omit<ENSIndexerConfig, "ensRainbowUrl" | "indexedChainIds" | "rpcConfigs" | "plugins"> {
extends Omit<
ENSIndexerConfig,
"ensRainbowUrl" | "indexedChainIds" | "rpcConfigs" | "plugins" | "chainEndBlocks"
> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 chainEndBlocks is omitted from SerializedENSIndexerConfig with no replacement property. Every other Map-typed field that's omitted gets a serialized counterpart (indexedChainIdsChainId[], rpcConfigsRecord<ChainIdString, SerializedRpcConfig>). Without a replacement, the active per-chain end-block configuration becomes invisible in whatever endpoint or log surfaces the serialized config, making it hard to confirm or debug which END_BLOCK_<chainId> values are in effect.

Replace the global START_BLOCK/END_BLOCK indexing-range config with per-chain end
blocks via END_BLOCK_<chainId> env vars (mirroring RPC_URL_<chainId>), parsed into
config.chainEndBlocks. Each constrains its chain's indexing end block independently
and may be set across any number of indexed chains.

blockrangeForChain() resolves the per-chain range; buildIndexedBlockranges
(@ensnode/ensnode-sdk) now takes a per-chain end-block map so indexing-status reaches
omnichain-completed for bounded multichain runs. Enables deterministic, reproducible
multichain checkpoints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants